package com.atguigu.tingshu.album.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.atguigu.tingshu.album.config.VodConstantProperties;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.mapper.TrackStatMapper;
import com.atguigu.tingshu.album.service.TrackInfoService;
import com.atguigu.tingshu.album.service.VodService;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.common.util.UploadFileUtil;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.album.TrackStat;
import com.atguigu.tingshu.model.base.BaseEntity;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.query.album.TrackInfoQuery;
import com.atguigu.tingshu.user.client.UserInfoFeignClient;
import com.atguigu.tingshu.vo.album.AlbumTrackListVo;
import com.atguigu.tingshu.vo.album.TrackInfoVo;
import com.atguigu.tingshu.vo.album.TrackListVo;
import com.atguigu.tingshu.vo.album.TrackStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.qcloud.vod.VodUploadClient;
import com.qcloud.vod.model.VodUploadRequest;
import com.qcloud.vod.model.VodUploadResponse;
import com.tencentcloudapi.vod.v20180717.models.MediaBasicInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaInfo;
import com.tencentcloudapi.vod.v20180717.models.MediaMetaData;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class TrackInfoServiceImpl extends ServiceImpl<TrackInfoMapper, TrackInfo> implements TrackInfoService {

	@Autowired
	private TrackInfoMapper trackInfoMapper;

    @Autowired
    private VodConstantProperties vodConstantProperties;

    @Autowired
    private VodService vodService;

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    @Autowired
    private UserInfoFeignClient userInfoFeignClient;

  /**
   * 1111 查询用户可以购买的声音的信息: 一次最多购买50集
   * @param trackId
   * @return
   */
  @Override
  public Object findUserTrackPaidList(Long trackId) {
    // 查询当前声音的详细信息
    TrackInfo trackInfo = this.getById(trackId);
    // 声音非空判断
    if (trackInfo == null || trackInfo.getId() == null){
      throw new GuiguException(201, "声音不存在!");
    }
    // 获取声音所属专辑的id
    Long albumId = trackInfo.getAlbumId();
    // 查询专辑的详细信息 能单独购买声音的专辑必须是单集付费专辑
    AlbumInfo albumInfo
            = albumInfoMapper.selectOne(
                    new LambdaQueryWrapper<AlbumInfo>()
                           .eq(AlbumInfo::getId, albumId) //专辑id
                           .eq(AlbumInfo::getPayType, "0103")//收费的专辑
                           .eq(AlbumInfo::getPriceType, "0201")//单集付费
                           .eq(AlbumInfo::getStatus, "0301")//审核通过
                           .eq(AlbumInfo::getIsOpen, "1"));//公开上架
    // 专辑非空判断
    if (albumInfo == null || albumInfo.getId() == null){
      throw new GuiguException(201, "专辑不存在!");
    }
    // 获取免费的集数
    Integer tracksForFree = albumInfo.getTracksForFree();
    // 获取当前登录用户的id
    Long userId = AuthContextHolder.getUserId();
    // 查出当前声音以及之后的所有集数的声音 可购买的声音列表(不包括该声音前的)
    List<TrackInfo> trackInfoList = this.list(new LambdaQueryWrapper<TrackInfo>()
                                             .eq(TrackInfo::getAlbumId, albumId)
                                             .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum()));
    // 查询当前声音所属的专辑有哪些声音已被当前用户购买过
    Map<String, Object> userPaidTrackMap = userInfoFeignClient.getUserPaidTrack(userId, albumId);
    // 从trackInfoList中删除已购买的声音
    List<TrackInfo> canBuyTrackList = trackInfoList.stream()
                                        .filter(t -> userPaidTrackMap.get(t.getId().toString()) == null // 保留没被购买过的
                                                && t.getOrderNum() > tracksForFree) // 保留非免费的集数
                                        .limit(50).toList(); // 一次性限制购买50条声音
    // 获取声音的单价
    BigDecimal price = albumInfo.getPrice();
    //返回结果初始化 前端购买时动态显示
    List<Object> result = new ArrayList();
    JSONObject resultJSON = new JSONObject();
    resultJSON.put("name", "本集");
    resultJSON.put("price", price); // 专辑声音对应的价格
    resultJSON.put("trackCount",1); // 记录购买集数
    result.add(resultJSON);

    // 获取全部可购买的声音的数量
    int total = canBuyTrackList.size();
    // 如果总集数大于1 则显示批量购买的选项
    if (total > 1){
      //每页显示的数据量
      int size = 10;
      //计算总页码
      int page = total % size== 0 ? total / size : total / size + 1;
      // 计算批量购买的选项的数据
      for (int i = 1; i <= page; i++) {
        resultJSON = new JSONObject();
        // 当前要显示的购买集数 本集 10 20 30 40 46
        Integer name = i * size;
        if (name <= total){
          //可购买的集数是10的倍数
          resultJSON.put("name", name + "集");
          //专辑声音对应的价格
          resultJSON.put("price", price.multiply(new BigDecimal(name)));
          //记录购买集数
          resultJSON.put("trackCount", name);
        } else {
          //可购买的集数不是10的倍数 即最后一页
          resultJSON.put("name",   total + "集");
          //专辑声音对应的价格
          resultJSON.put("price", price.multiply(new BigDecimal(total)));
          //记录购买集数
          resultJSON.put("trackCount",total);
        }
        result.add(resultJSON);
      }
    }

    return result;
  }

  /**
   * 查询声音的详细信息,和可以购买的声音的列表
   * @param trackId
   * @return
   */
  @Override
  public List<TrackInfo> getTrackInfoList(Long trackId, Integer trackCount) {
    //查询当前声音的详细信息
    TrackInfo trackInfo = getById(trackId);
    if(trackInfo == null || trackInfo.getId() == null){
      return null;
    }
    //获取专辑的id
    Long albumId = trackInfo.getAlbumId();
    //查询专辑的详细信息
    AlbumInfo albumInfo =
            albumInfoMapper.selectOne(
                    new LambdaQueryWrapper<AlbumInfo>()
                            .eq(AlbumInfo::getId, albumId)
                            .eq(AlbumInfo::getPriceType, "0201")//单集付费
                            .eq(AlbumInfo::getPayType, "0103")//收费的专辑
                            .eq(AlbumInfo::getStatus, "0301")//审核通过
                            .eq(AlbumInfo::getIsOpen, "1"));//公开上架
    if(albumInfo == null || albumInfo.getId() == null){
      return null;
    }
    //获取免费的集数
    Integer tracksForFree = albumInfo.getTracksForFree();
    //获取本次登录的用户
    Long userId = AuthContextHolder.getUserId();
    //查询出当前声音以及当前声音后的全部声音: list1
    List<TrackInfo> trackInfoList = list(
            new LambdaQueryWrapper<TrackInfo>()
                    .eq(TrackInfo::getAlbumId, albumId)
                    .ge(TrackInfo::getOrderNum, trackInfo.getOrderNum()));
    //查询这个用户购买过这个声音所属的专辑的哪些声音: map
    Map<String, Object> userPaidTrackMap =
            userInfoFeignClient.getUserPaidTrack(userId, albumId);
    //从list1中剔除map的全部的数据,限制<=50即可
    trackInfoList = trackInfoList.stream()
                                 .filter(t->userPaidTrackMap.get(t.getId().toString()) == null //过滤掉购买过的
                                         && t.getOrderNum() > tracksForFree)//过滤掉免费的
                                 .limit(trackCount)
                                 .collect(Collectors.toList());
    //返回
    return trackInfoList;
  }

  /**
     * 1110 查询声音的统计数据
     * @param trackId
     * @return
     */
    @Override
    public Object getTrackStatVo(Long trackId) {
        // 查询声音的全部统计数据
        List<TrackStat> trackStatList = trackStatMapper.selectList(new LambdaQueryWrapper<TrackStat>()
                                                                        .eq(TrackStat::getTrackId, trackId));
        // 转化为map
        Map<String, Integer> typeToNumMap = trackStatList.stream().collect(Collectors.toMap(
                TrackStat::getStatType,
                TrackStat::getStatNum
        ));
        // 返回结果初始化
        TrackStatVo trackStatVo = new TrackStatVo();
        trackStatVo.setPlayStatNum(typeToNumMap.get(SystemConstant.TRACK_STAT_PLAY));
        trackStatVo.setCollectStatNum(typeToNumMap.get(SystemConstant.TRACK_STAT_COLLECT));
        trackStatVo.setPraiseStatNum(typeToNumMap.get(SystemConstant.TRACK_STAT_PRAISE));
        trackStatVo.setCommentStatNum(typeToNumMap.get(SystemConstant.TRACK_STAT_COMMENT));
        // 返回结果
        return trackStatVo;
    }



  /**
     * 查询指定专辑的分页声音列表
     * @param albumId
     * @return
     */
    @Override
    public Object findAlbumTrackPage(Page<AlbumTrackListVo> page, Long albumId) {
        // 分页查询专辑的声音列表
        IPage<AlbumTrackListVo> TrackListPage
                = trackInfoMapper.selectAlbumTrackPage(page, albumId);
        // 获取专辑的声音列表
        List<AlbumTrackListVo> albumTrackListVoList = TrackListPage.getRecords();
        // 根据id查询专辑的数据
        AlbumInfo albumInfo = albumInfoMapper.selectById(albumId);
        // 获取专辑的付费类型: 0101-免费 0102-VIP免费 0103-付费
        String payType = albumInfo.getPayType();
        // 获取专辑的免费集数
        Integer tracksForFree = albumInfo.getTracksForFree();
        // 获取当前登录用户的id
        Long userId = AuthContextHolder.getUserId();
        // 根据专辑的不同付费类型做不同的处理
        switch (payType){
            // 免费专辑
            case "0101" -> {
                return TrackListPage;
            }
            // vip免费专辑
            case "0102" -> {
                // 查询当前登录用户的信息
                UserInfo userInfo = userInfoFeignClient.getUserInfo(userId);
                // 判断该用户的VIP状态
                if (userInfo.getIsVip().equals(0)){
                    // 不是VIP 将专辑的声音修改为收费 除了免费的集数
                     if (userInfo.getIsVip().equals(0)){
                         List<AlbumTrackListVo> albumTrackListVoListChecked = setAlbumTrackListVo(albumTrackListVoList, tracksForFree);
                         // 将TrackListPage中旧的数据覆盖
                         TrackListPage.setRecords(albumTrackListVoListChecked);
                     }
                }
                // 是VIP直接返回
                return TrackListPage;
            }
            // 付费专辑
            case "0103" -> {
            // 获取专辑的价格类型
                String priceType = albumInfo.getPriceType();
                if (priceType.equals("0202")){
                    // 0202-整张专辑收费 校验用户是否购买过这张专辑 a.将来的订单表可以查 b.用户购买记录表
                    Boolean paid = userInfoFeignClient.getUserPaidAlbum(userId, albumId);
                    if (!paid){
                        // 没有购买过专辑 将专辑的声音修改为收费 除了免费的集数
                        List<AlbumTrackListVo> albumTrackListVoListChecked = setAlbumTrackListVo(albumTrackListVoList, tracksForFree);
                        // 将TrackListPage中旧的数据覆盖
                        TrackListPage.setRecords(albumTrackListVoListChecked);
                    }
                } else {
                    // 0201-专辑中单集声音收费
                    Map<String, Object> userPaidTrackMap = userInfoFeignClient.getUserPaidTrack(userId, albumId);
                    // 遍历专辑中的所有声音 将没有购买过的设置为收费
                    List<AlbumTrackListVo> albumTrackListVoListChecked = albumTrackListVoList.stream().peek(track -> {
                        // 将除了免费的集数和已购买的声音之外的其他声音设置为需要购买
                        if (track.getOrderNum() > tracksForFree && userPaidTrackMap.get(track.getTrackId().toString()) == null) {
                            track.setIsShowPaidMark(true);
                        }
                    }).toList();
                    // 将TrackListPage中旧的数据覆盖
                    TrackListPage.setRecords(albumTrackListVoListChecked);
                }
                return TrackListPage;
            }
        }
        // 返回结果
        return TrackListPage;
    }

    /**
     * 设置声音的收费信息除了免费的集数
     * @param albumTrackListVoList
     * @param tracksForFree
     * @return
     */
    private List<AlbumTrackListVo> setAlbumTrackListVo(List<AlbumTrackListVo> albumTrackListVoList, Integer tracksForFree){
       return albumTrackListVoList.stream().peek(track -> {
            // 判断声音是否为免费的
            if (track.getOrderNum() > tracksForFree) {
                // 设置为收费
                track.setIsShowPaidMark(true);
            }
       }).toList();
    }
    /**
     * 声音的上传
     * @param file
     * @return JSONObject
     */
    @SneakyThrows
    @Override
    public JSONObject uploadTrack(MultipartFile file) {
        JSONObject jsonObject = new JSONObject();
        // 先将文件存储在服务端本地的临时目录
        String tempPath = UploadFileUtil.uploadTempPath(vodConstantProperties.getTempPath(), file);
        // 初始化一个上传客户端的对象
        VodUploadClient client = new VodUploadClient(vodConstantProperties.getSecretId(), vodConstantProperties.getSecretKey());
        // 构造上传请求对象
        VodUploadRequest request = new VodUploadRequest();
        request.setMediaFilePath(tempPath);
        // 将文件上传到腾讯云
        VodUploadResponse response = client.upload(vodConstantProperties.getRegion(), request);
        // 解析文件的唯一标识
        String fileId = response.getFileId();
        jsonObject.put("mediaFileId", fileId);
        // 获取播放地址
        String mediaUrl = response.getMediaUrl();
        jsonObject.put("mediaUrl", mediaUrl);
        // 返回结果
        return jsonObject;
    }


    @Autowired
    private TrackStatMapper trackStatMapper;

    /**
     * 声音的保存
     * @param trackInfoVo
     * @return
     */
    @Override
    public void saveTrackInfo(TrackInfoVo trackInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        // 1.获取专辑Id
        Long albumId = trackInfoVo.getAlbumId();
        // 查询该专辑排序最靠后的一条声音
        TrackInfo lastTrackInfo = this.getOne(new LambdaQueryWrapper<TrackInfo>()
                .eq(TrackInfo::getAlbumId, albumId)
                .orderByDesc(TrackInfo::getOrderNum)
                .last("limit 1"));
        // 有上一条则在上一条的orderNum + 1 没有上一条 则为1
        int orderNum = lastTrackInfo == null ? 1 : lastTrackInfo.getOrderNum() + 1;

        // 2.创建一个声音对象 给属性赋值
        TrackInfo trackInfo = new TrackInfo();
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        trackInfo.setUserId(userId);
        trackInfo.setOrderNum(orderNum);
        // 通过文件的唯一标识,去腾讯云点播查询文件的详细信息
       MediaInfo[] mediaInfos = vodService.getFileInfoBYFileId(trackInfo.getMediaFileId());
       if (mediaInfos == null || mediaInfos.length == 0){
           throw new GuiguException(201, "保存声音失败, 音频文件不存在");
       }
       // 获取本次查询到的文件信息
        MediaBasicInfo basicInfo = mediaInfos[0].getBasicInfo();
        MediaMetaData metaData = mediaInfos[0].getMetaData();
        // 给声音对象的属性赋值
        trackInfo.setMediaType(basicInfo.getType());
        trackInfo.setMediaSize(metaData.getSize());
        trackInfo.setMediaDuration(new BigDecimal(metaData.getDuration().toString()));
        trackInfo.setMediaFileId(trackInfoVo.getMediaFileId());
        trackInfo.setMediaUrl(basicInfo.getMediaUrl());
        // 3.将声音保存到数据库
        if (!save(trackInfo)){
            throw new GuiguException(201, "保存声音失败");
        }
        // 4.初始化统计数据
        this.initTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PLAY); // 播放量0701
        this.initTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COLLECT); // 收藏量0702
        this.initTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_PRAISE); // 点赞量0703
        this.initTrackStat(trackInfo.getId(), SystemConstant.TRACK_STAT_COMMENT); // 评论量0704

    }

    /**
     * 查询当前用户的分页声音列表
     * @param trackInfoQuery
     * @return
     */
    @Override
    public Page<TrackListVo> findUserAlbumPage(Page<TrackInfo> trackInfoPage, TrackInfoQuery trackInfoQuery) {
        Long userId = AuthContextHolder.getUserId();
        trackInfoQuery.setUserId(userId); // 设置用户Id
        return trackInfoMapper.findUserAlbumPage(trackInfoPage, trackInfoQuery);
    }

    /**
     * 根据专辑Id删除声音
     * @param trackId
     * @return
     */
    @Override
    public void removeTrackInfo(Long trackId) {
        // 先判断该声音是否存在
        TrackInfo trackInfo = this.getById(trackId);
        if (trackInfo == null){
            return; // 不存在直接结束方法
        }
        if (!removeById(trackId)){
             throw new GuiguException(201, "删除声音失败");
         }
        // 删除统计数据
        int row = trackStatMapper.delete(new LambdaQueryWrapper<TrackStat>()
                .eq(TrackStat::getTrackId, trackId));
        if (row <= 0){
            throw new GuiguException(201, "删除声音统计数据失败");
        }
        // 逻辑层面删除云服务上的音频文件
        if (vodService.getFileInfoBYFileId(trackInfo.getMediaFileId()) != null){
            vodService.removeFile(trackInfo.getMediaFileId());
        }
    }

    /**
     * 修改数据时回显数据
     * @param trackId
     * @return
     */
    @Override
    public TrackInfo getTrackInfo(Long trackId) {
        Long userId = AuthContextHolder.getUserId();
        TrackInfo trackInfo = this.getOne(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getId, trackId)
                        .eq(TrackInfo::getUserId, userId));
        if (trackInfo == null){
            throw new GuiguException(201, "声音数据不存在");
        }
        return trackInfo;
    }

    /**
     * 修改声音
     * @param trackId
     * @param trackInfoVo
     * @return
     */
    @Override
    public void updateTrackInfo(Long trackId, TrackInfoVo trackInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        // 先根据trackId查询声音数据是否存在
        TrackInfo trackInfo = this.getOne(new LambdaQueryWrapper<TrackInfo>()
                .eq(BaseEntity::getId, trackId)
                .eq(TrackInfo::getUserId, userId));
        if (trackInfo == null){
            // 声音数据不存在直接结束方法
            return;
        }
        // 复制属性
        BeanUtils.copyProperties(trackInfoVo, trackInfo);
        // 判断声音文件是否有变化
        String mediaFileIdDb = trackInfo.getMediaFileId();
        String mediaFileId = trackInfoVo.getMediaFileId();
        if (!mediaFileId.equals(mediaFileIdDb)){
            // 不相同 则删除数据库中的文件
            vodService.removeFile(mediaFileIdDb);
            // 查询新的声音文件的详细信息
            MediaInfo[] mediaInfos = vodService.getFileInfoBYFileId(mediaFileId);
            if (mediaInfos == null || mediaInfos.length == 0){
                throw new GuiguException(201, "保存声音失败, 音频文件不存在");
            }
            trackInfo.setMediaFileId(mediaFileId);
            // 获取本次查询的文件信息
            MediaInfo mediaInfo = mediaInfos[0];
            // 获取基础信息
            MediaBasicInfo basicInfo = mediaInfo.getBasicInfo();
            trackInfo.setMediaType(basicInfo.getType());
            trackInfo.setMediaUrl(basicInfo.getMediaUrl());
            // 获取元数据
            MediaMetaData metaData = mediaInfo.getMetaData();
            trackInfo.setMediaSize(metaData.getSize());
            trackInfo.setMediaDuration(new BigDecimal(metaData.getAudioDuration().toString()));
        }
        // 修改声音数据
        if (!updateById(trackInfo)){
            throw new GuiguException(201, "修改声音失败");
        }
    }



  /**
     * 初始化统计数据
     * @param trackId
     * @param statType
     * @return null
     */
    private void initTrackStat(Long trackId, String statType) {
        // 创建一个声音统计数据对象
        TrackStat trackStat = new TrackStat();
        // 赋值
        trackStat.setStatNum(0);
        trackStat.setTrackId(trackId);
        trackStat.setStatType(statType);
        // 新增
        trackStatMapper.insert(trackStat);
    }
}
